package crypto.process;

import crypto.reference.References;

import crypto.util.RandomCrypto;
import crypto.util.Util;

/**
 * DOCUMENT ME!
 *
 * @author gato
 */
public class DeleteEmptySpace {
  private int[][]              matrix    = new int[4][2];
  private char[]               arrayText;
  private String               position  = "";
  private boolean              flag      = true;
  private DistributionWeight[] distri    = new DistributionWeight[26];

  /**
   * Metodo que suprime los espacios vacios de la cadena de texto agregando caracteres
   * generados al azar en su lugar.
   *
   * @param text [String]
   * @param textSize DOCUMENT ME!
   * @param block DOCUMENT ME!
   *
   * @return texto modificado [String]
   */
  public String supressEmpty(String text, int textSize, int block) {
    char character;
    int  auxPos = 0;

    arrayText = text.toCharArray();

    //Genera array con los pesos de distribucion de cada letra.
    this.charDistribution(text);

    //Inicializo la Matriz
    initMatrix();

    //Analizo cada caracter del array y trabajo con su posicion
    for (int i = 0; i < arrayText.length; i++) {
      character   = arrayText[i];
      auxPos      = i;

      //Si es un caracter vacio, le ingreso una letra aleatoria, convierto
      //su posicion, y es guardada en una cadena string.
      if (character == ' ') {
        char letter;
        letter         = this.randomEstimationLetter(0);
        arrayText[i]   = letter;

        if (i < textSize) {
          matrix(auxPos, block);
        }
      }
    }

    //agrego valor de la ultima posicion de espacios
    this.matrix(textSize, block);

    return new String(arrayText);
  }

  /**
   * DOCUMENT ME!
   *
   * @param text DOCUMENT ME!
   * @param reference DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   */
  public String insertEmpty(String text, References reference) {
    int auxPos = 0;

    arrayText = text.toCharArray();

    //Inicializo la Matriz
    this.setValuesMatrix(reference);

    int[] arrayPos = this.obtainPositions(reference);
    int aux = 0;

    for (int i = 0; i < arrayPos.length-1; i++) {
        aux = i;
      arrayText[arrayPos[i]] = ' ';
    }
    
    reference.setPosFinal( arrayPos[ arrayPos.length-1 ] );

    return new String(arrayText).trim();
  }

  /**
   * Metodo para inicializar la matriz con la que se procesaran los numeros utilizados para
   * las posiciones.
   */
  private void initMatrix() {
    java.security.SecureRandom random = new java.security.SecureRandom();

    for (int i = 0; i < 4; i++) {
      for (int j = 0; j < 2; j++) {
        matrix[i][j] = RandomCrypto.getRandomInt(1000);
      }
    }
  }

  private void setValuesMatrix(References reference) {
    this.matrix = reference.getDeleteMatrix();
  }

  /**
   * Metodo que aplica una combinacion de los valores de la matriz generada a la posicion,
   * intercalando los valores de la matriz que se aplican y convirtiendo el resultado de la
   * posicion a un base de 36.
   *
   * @param posic [Integer]
   * @param bloque DOCUMENT ME!
   */
  private void matrix(int posic, int block) {
    int    newPos = 0;
    String place  = "";
    block += 8;

    //Hago la siguiente secuencia de forma intercalada
    if (flag) {
      newPos     = posic + matrix[0][0] + matrix[1][1] + matrix[2][0] + matrix[3][1];
      flag       = false;
      place      = Util.convertDecimalB36(newPos, block);
      position   = position.concat(place);
    } else {
      newPos     = posic + matrix[3][0] + matrix[2][1] + matrix[1][0] + matrix[0][1];
      flag       = true;
      place      = Util.convertDecimalB36(newPos, block);
      position   = position.concat(place);
    }
  }

  private int[] obtainPositions(References reference) {
      
    int   length         = Util.estimateLengthConvertion(reference.getCompleteBlock() + 8);
    int   cantPosition   = reference.getDeletePosition().length() / length;
    int[] arrayPositions = new int[cantPosition];

    flag = true;
    int   start          = 0;

    for (int i = 0; i < cantPosition; i++, start += length) {
      String pos = reference.getDeletePosition().substring(start, (start + length));

      //Hago la siguiente secuencia de forma intercalada
      if (flag) {
        int position = Util.convertB36Decimal(pos);
        position = (position - matrix[0][0] - matrix[1][1] - matrix[2][0] - matrix[3][1]);
        flag                = false;
        arrayPositions[i]   = position;
      } else {
        int position = Util.convertB36Decimal(pos);
        position = (position - matrix[3][0] - matrix[2][1] - matrix[1][0] - matrix[0][1]);
        flag                = true;
        arrayPositions[i]   = position;
      }
      
    }

    return arrayPositions;
  }

  private char randomEstimationLetter(int minWeight) {
    int pos = RandomCrypto.getRandomInt(distri.length);

    for (int i = pos; i < (distri.length - pos); i++) {
      if (distri[i].getWeight() == minWeight) {
        distri[i].setWeight(minWeight + 1);

        return distri[i].getLetter();
      }
    }

    for (int i = pos - 1; i > 0; i--) {
      if (distri[i].getWeight() == minWeight) {
        return distri[i].getLetter();
      }
    }

    return this.randomEstimationLetter(++minWeight);
  }

  private void charDistribution(String text) {
    char letter = 65;

    for (int i = 0; i < distri.length; i++) {
      distri[i] = new DistributionWeight();
      distri[i].setLetter(letter);
      distri[i].establishWeight(letter, text);
      letter++;
    }
  }

  /**
   * DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   */
  public String getPosition() {
    return this.position;
  }

  /**
   * DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   */
  public int[][] getMatrix() {
    return this.matrix;
  }
}
